package main

import (
	"fmt"
	"sync"
	"time"
)

func main() {

	// 如果是 rLock() 这个协程先执行，就会完整的执行结束，wLock() 才会执行，因为 rLock() 中的读锁会阻塞 wLock() 试图获取写锁的动作；
	go rLock()

	// 尝试获取同一把锁对象的写锁，如果该锁对象已经被加了读锁，则尝试获取写锁的动作会被阻塞
	go wLock()

	//go lock()

	time.Sleep(2 * time.Second)
}

// 这里第 2 次进入循环不会出现死锁
func rLock() {

	// 这里的 lock 和 wLock() 中的 lock 不是同一个 lock
	lock := sync.RWMutex{}
	println("r:{}", &lock)

	// 每次循环都能获取到锁，读锁之前不互斥
	for i := 0; i < 3; i++ {
		lock.RLock()
		defer lock.RUnlock()
		fmt.Println("rLock:", i)
	}
}

// 尝试对同一个锁对象加写锁
func wLock() {

	// 这里的 lock 结构和 rLock() 中获取到的不是同一个
	lock := sync.RWMutex{}
	println("w:{}", &lock)

	// 循环 1 会获取到写锁，但是循环 1 结束的时候并不会释放；
	// 循环 2 尝试获取写锁的动作会因为循环 1 中没有释放而失败，所以 wLock：只打印出了 1 条
	for i := 0; i < 3; i++ {
		lock.Lock()
		defer lock.Unlock()
		fmt.Println("wLock:", i)
	}
}

// 死锁：for 循环整个执行结束后才会以弹栈的方式执行 defer 释放锁，所以在进入第 2 次循环试图获取锁的时候，锁还没释放，就死锁了
func lock() {
	lock := sync.Mutex{}
	for i := 0; i < 3; i++ {
		lock.Lock()
		defer lock.Unlock()
		fmt.Println("lock:", i)
	}
}
